/*
*  Copyright 2019-2020 Zheng Jie
*
*  Licensed under the Apache License, Version 2.0 (the "License");
*  you may not use this file except in compliance with the License.
*  You may obtain a copy of the License at
*
*  http://www.apache.org/licenses/LICENSE-2.0
*
*  Unless required by applicable law or agreed to in writing, software
*  distributed under the License is distributed on an "AS IS" BASIS,
*  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*  See the License for the specific language governing permissions and
*  limitations under the License.
*/
package com.mcx.modules.service.impl;

import cn.hutool.core.date.DateTime;
import com.mcx.modules.data.EnumDefine;
import com.mcx.modules.data.localdata.create.*;
import com.mcx.modules.domain.*;
import com.mcx.modules.entity.Role_BackpackAddItemEntity;
import com.mcx.modules.entity.Role_BackpackItemChangeEntity;
import com.mcx.modules.service.*;
import lombok.RequiredArgsConstructor;
import com.mcx.modules.repository.PlayerBackpackRepository;
import com.mcx.modules.service.dto.PlayerBackpackDto;
import com.mcx.modules.service.dto.PlayerBackpackQueryCriteria;
import com.mcx.modules.service.mapstruct.PlayerBackpackMapper;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import com.mcx.utils.PageUtil;
import com.mcx.utils.QueryHelp;

import java.util.*;
import java.io.IOException;
import javax.servlet.http.HttpServletResponse;

/**
* @website https://el-admin.vip
* @description 服务实现
* @author mcx
* @date 2022-04-30
**/
@Service
@RequiredArgsConstructor
public class PlayerBackpackServiceImpl implements PlayerBackpackService {

    private final PlayerBackpackRepository playerBackpackRepository;
    private final PlayerBackpackMapper playerBackpackMapper;

    private final PlayerEquipService playerEquipService;
    private final PlayerItemService playerItemService;
    private final PlayerMaterialService playerMaterialService;
    private final LogGoodsinService logGoodsinService;

    @Override
    public Map<String,Object> queryAll(PlayerBackpackQueryCriteria criteria, Pageable pageable){
        Page<PlayerBackpack> page = playerBackpackRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder),pageable);
        return PageUtil.toPage(page.map(playerBackpackMapper::toDto));
    }

    @Override
    public List<PlayerBackpackDto> queryAll(PlayerBackpackQueryCriteria criteria){
        return playerBackpackMapper.toDto(playerBackpackRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder)));
    }

    @Override
    @Transactional
    public PlayerBackpackDto findById(Integer id) {
        PlayerBackpack playerBackpack = playerBackpackRepository.findById(id).orElseGet(PlayerBackpack::new);
        return playerBackpackMapper.toDto(playerBackpack);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public PlayerBackpackDto create(PlayerBackpack resources) {
        return playerBackpackMapper.toDto(playerBackpackRepository.save(resources));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(PlayerBackpack resources) {
        PlayerBackpack playerBackpack = playerBackpackRepository.findById(resources.getId()).orElseGet(PlayerBackpack::new);
        playerBackpack.copy(resources);
        playerBackpackRepository.save(playerBackpack);
    }

    @Override
    public void deleteAll(Integer[] ids) {
        for (Integer id : ids) {
            playerBackpackRepository.deleteById(id);
        }
    }

    @Override
    public List<Role_BackpackItemChangeEntity> add(Integer playerId, EnumDefine.GoodsInType goodsInType, Role_BackpackAddItemEntity entity) {
        List<Role_BackpackAddItemEntity> lst = new ArrayList<Role_BackpackAddItemEntity>();
        lst.add(entity);

        return add(playerId, goodsInType, lst);
    }

    @Override
    public List<Role_BackpackItemChangeEntity> add(Integer playerId, EnumDefine.GoodsInType goodsInType, List<Role_BackpackAddItemEntity> lst) {
        List<Role_BackpackItemChangeEntity> changeList = new ArrayList<Role_BackpackItemChangeEntity>();

            for (int i = 0; i < lst.size(); i++)
            {
                List<Role_BackpackItemChangeEntity> lstChange = add(playerId, goodsInType, lst.get(i).GoodsType, lst.get(i).GoodsId, lst.get(i).GoodsCount);
                if (lstChange != null)
                {
                    changeList.addAll(lstChange);
                }
            }
            return changeList;
//        }
    }

    private List<Role_BackpackItemChangeEntity> add(Integer playerId, EnumDefine.GoodsInType goodsInType, byte goodsType, int goodsId, int goodsCount){
        List<Role_BackpackItemChangeEntity> changeList = new ArrayList<Role_BackpackItemChangeEntity>();
        int goodsServerId = 0;
        int speed = Integer.parseInt(DateTime.now().toString("hhMMssfff")); //种子

        for (int i = 0; i < goodsCount; i++)
        {
//            //1.加入物品库 装备 道具 材料（根据物品类型 加入对应的物品表 如果是装备 要进行随机属性和随机属性值处理）
//            switch (goodsType)
//            {
//                case EnumDefine.GoodsType.Equip:
//                    PlayerEquip equipEntity = new PlayerEquip(){{
//                        setStatus(1);
//                        setPlayerId(playerId);
//                        setEquipId(goodsId);
//                    }};
//
//                    //拿到基础装备信息
//                    EquipEntity baseEntity = EquipDBModel.getInstance().Get(goodsId);
//
//                    //基础信息
//                    equipEntity.setBaseAttr1Type(baseEntity.BackAttrOneType);
//                    equipEntity.setBaseAttr1Value(baseEntity.BackAttrOneValue);
//                    equipEntity.setBaseAttr2Type(baseEntity.BackAttrTwoType);
//                    equipEntity.setBaseAttr2Value(baseEntity.BackAttrTwoValue);
//
//                    //随机属性
//                    //1.计算出随机属性的数量 一共是8个属性 我们随机取2-6个 也可以根据装备等级不同 随机数不同
//                    int attrCount = new Random(speed).nextInt(2);
//                    speed += 100;
//
//                    //0=HP 1=MP 2=攻击 3=防御 4=命中 5=闪避 6=暴击 7=抗性
//                    Integer[] arr = new Integer[] { 0, 1, 2, 3, 4, 5, 6, 7 };
//
//                    List<Integer> lst = new ArrayList<Integer>();
//                    Collections.addAll(lst, arr);
//
//                    for (int j = 0; j < attrCount; j++)
//                    {
//                        //随机获取一个索引 对他进行随机值
//                        //随机算法 要根据具体的项目 结合数值策划提供的算法公式来做 比如根据角色的等级 VIP等级 运气值等等来计算
//                        //这里是进行最基础的随机
//
//                        int index = new Random(speed).nextInt(lst.size());
//                        speed += 100;
//
//                        switch (lst.get(index))
//                        {
//                            case 0:
//                                equipEntity.setHp(new Random(speed).nextInt((int)(baseEntity.HP * 1.5f)));
//                                speed += 100;
//                                break;
//                            case 1:
//                                equipEntity.setMp (new Random(speed).nextInt((int)(baseEntity.MP * 1.5f))) ;
//                                speed += 100;
//                                break;
//                            case 2:
//                                equipEntity.setAttack (new Random(speed).nextInt((int)(baseEntity.Attack * 1.5f))) ;
//                                speed += 100;
//                                break;
//                            case 3:
//                                equipEntity.setRes (new Random(speed).nextInt((int)(baseEntity.Res * 1.5f))) ;
//                                speed += 100;
//                                break;
//                            case 4:
//                                equipEntity.setHit (new Random(speed).nextInt((int)(baseEntity.Hit * 1.5f))) ;
//                                speed += 100;
//                                break;
//                            case 5:
//                                equipEntity.setDefense ( new Random(speed).nextInt((int)(baseEntity.Defense * 1.5f)));
//                                speed += 100;
//                                break;
//                            case 6:
//                                equipEntity.setDodge (new Random(speed).nextInt((int)(baseEntity.Dodge * 1.5f))) ;
//                                speed += 100;
//                                break;
//                            case 7:
//                                equipEntity.setCri (new Random(speed).nextInt((int)(baseEntity.Cri * 1.5f)) );
//                                speed += 100;
//                                break;
//                        }
//
//                        //这个索引 也就是属性用过了 就移除
//                        lst.remove(index);
//                    }
//                    playerEquipService.create(equipEntity);
//                    break;
//                case EnumDefine.GoodsType.Item:
//                    PlayerItem itemEntity = new PlayerItem(){{
//                        setStatus(1);
//                        setRoleId(playerId);
//                        setItemId(goodsId);
//                    }};
//                    playerItemService.create(itemEntity);
//                    break;
//                case EnumDefine.GoodsType.Material:
//                    PlayerMaterial materialEntity = new PlayerMaterial(){{
//                        setStatus(1);
//                        setRoleId(playerId);
//                        setMaterialId(goodsId);
//                    }};
//                    playerMaterialService.create(materialEntity);
//                    break;
//            }

//            goodsServerId = retValue.OutputValues["Id"].ToInt(); //物品的服务器端编号

            //2.添加物品入库日志（要先从 步骤1 拿到物品的服务器端编号）
            LogGoodsin goodsInEntity = new LogGoodsin(){{
                setStatus(1);
                setRoleId(playerId);
                setType(goodsInType.ordinal());
                setGoodsType((int) goodsType);
                setGoodsId(goodsId);
                setGoodsServerId(1);
            }};
            logGoodsinService.create(goodsInEntity);
        }

        //3.加入背包（要进行物品的叠加处理）
        //(1).拿到物品基础表的叠加数量 装备是1 道具材料是20
        //(2).如果叠加数量是1 跳过此步骤 查询库中 该物品叠加数量最低的背包项 比如回血药 有两个背包项 20 5，那就按物品叠加数量正顺序排序 取出第一个5
        //(3).如果叠加数量是1 跳过此步骤 对这个背包项进行填充 5 -> 20
        //(4).进行剩余物品的处理 根据剩余物品的数量 该物品的叠加数量上限 动态创建背包项目 直到剩余物品全部添加完毕


            // (1).拿到物品基础表的叠加数量 装备是1 道具材料是20
        int goodsOverlayCount = 1; //物品叠加数量
//        switch (goodsType)
//        {
//            case (byte) EnumDefine.GoodsType.Item.ordinal():
//                ItemEntity itemEntity = ItemDBModel.getInstance().Get(goodsId);
//                if (itemEntity != null)
//                {
//                    goodsOverlayCount = itemEntity.maxAmount;
//                }
//                break;
//            case (byte) EnumDefine.GoodsType.Material.ordinal():
//                MaterialEntity materialEntity = MaterialDBModel.getInstance().Get(goodsId);
//                if (materialEntity != null)
//                {
//                    goodsOverlayCount = materialEntity.maxAmount;
//                }
//                break;
//        }
            

            // (2).如果叠加数量是1 跳过此步骤 查询库中 该物品叠加数量最低的背包项 比如回血药 有两个背包项 20 5，那就按物品叠加数量正顺序排序 取出第一个5
        PlayerBackpackDto backpackEntity = null;
        if (goodsOverlayCount > 1)
        {
//            List<PlayerBackpackDto> retList = queryAll(new PlayerBackpackQueryCriteria() {{
//                setPlayerId(playerId);
//                setGoodsType((int) goodsType);
//                setGoodsId(goodsId);
//            }}, new PageRequest(1, 1, Sort.Direction.DESC, ""));
//
//
//            if (retList != null && retList.size() > 0)
//            {
//                backpackEntity = retList.get(0);
//            }
        }
            

            // (3).如果叠加数量是1 跳过此步骤 如果能查到背包项 对这个背包项进行填充 5 -> 20
        if (goodsOverlayCount > 1)
        {
            if (backpackEntity != null)
            {
                //需要填充的数量 = 物品的叠加数量 - 当前背包项的叠加数量
                int needCount = goodsOverlayCount - backpackEntity.getGoodsOverlayCount();

                if (needCount > 0)
                {
                    int currOverlayCount = 0;
                    if (goodsCount > needCount)
                    {
                        //当前叠加数量 = 物品叠加数量
                        currOverlayCount = goodsOverlayCount;
                        goodsCount -= needCount; //本次添加的物品数量减少
                    }
                    else
                    {
                        //当前叠加数量 = 原来的叠加数量 + 本次添加的物品数量
                        currOverlayCount = backpackEntity.getGoodsOverlayCount() + goodsCount;
                        goodsCount = 0;
                    }

                    backpackEntity.setGoodsOverlayCount(currOverlayCount);
                    update(playerBackpackMapper.toEntity(backpackEntity));

                    PlayerBackpackDto finalBackpackEntity = backpackEntity;
                    changeList.add(new Role_BackpackItemChangeEntity()
                    {{
                        BackpackId = finalBackpackEntity.getId();
                        Type = (byte) EnumDefine.BackpackItemChangeType.Update.ordinal();
                        GoodsType = (byte)(int) finalBackpackEntity.getGoodsType();
                        GoodsId = finalBackpackEntity.getGoodsId();
                        GoodsCount = finalBackpackEntity.getGoodsOverlayCount();
                        GoodsServerId = finalBackpackEntity.getGoodsServerId();
                    }});

//                    log.info("背包项修改了==>" + backpackEntity.getId());
                }
            }
        }
            

            // (4).进行剩余物品的处理 根据剩余物品的数量 该物品的叠加数量上限 动态创建背包项目 直到剩余物品全部添加完毕
        while (goodsCount > 0)
        {
            int currOverlayCount = 0;
            if (goodsCount > goodsOverlayCount)
            {
                currOverlayCount = goodsOverlayCount;
                goodsCount -= goodsOverlayCount;
            }
            else
            {
                currOverlayCount = goodsCount;
                goodsCount = 0;
            }

            int finalCurrOverlayCount = currOverlayCount;
            PlayerBackpack entity = new PlayerBackpack(){{
                setStatus(1);
                setPlayerId(playerId);
                setGoodsType((int)goodsType);
                setGoodsId(goodsId);
                setGoodsOverlayCount(finalCurrOverlayCount);
                setGoodsServerId(0);
            }};

            create(entity);
//            entity.Id(); = retValue.GetOutputValue<int>("Id");
//            log.info("背包项添加了==>" + entity.getId());

            changeList.add(new Role_BackpackItemChangeEntity()
            {{
                BackpackId = entity.getId();
                Type = (byte) EnumDefine.BackpackItemChangeType.Add.ordinal();
                GoodsType = (byte)(int)entity.getGoodsType();
                GoodsId = entity.getGoodsId();
                GoodsCount = entity.getGoodsOverlayCount();
                GoodsServerId = entity.getGoodsServerId();
            }});
        }

        return changeList;
    }

    private Boolean Reduce(Integer playerId, Integer playerBackpackId, Integer goodsType, Integer goodsId, Integer goodsServerId, Integer count, EnumDefine.GoodsOutType outType){

        return false;
    }

    @Override
    public Boolean sellToSys(Integer playerId, Integer playerBackpackId, Integer goodsType, Integer goodsId, Integer goodsServerId, Integer sellCount) {
        return Reduce(playerId, playerBackpackId, goodsType, goodsId, goodsServerId, sellCount, EnumDefine.GoodsOutType.SellToNpc);
    }

    @Override
    public Boolean useItem(Integer playerId, Integer playerBackpackId, Integer goodsId) {
        return null;
    }
}